package com.weishi.project.speedometer.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.weishi.common.enums.RedisConstants;
import com.weishi.common.utils.DateUtils;
import com.weishi.common.utils.GPSUtil;
import com.weishi.framework.redis.RedisCache;
import com.weishi.framework.web.domain.AjaxResult;
import com.weishi.project.speedometer.service.ISpeedometerService;
import com.weishi.project.speedometer.vo.DevInfo;
import com.weishi.project.speedometer.vo.MqttDataVo;
import com.weishi.project.speedometer.vo.RealTimeDataVo;
import com.weishi.project.training.domain.*;
import com.weishi.project.training.service.*;
import com.weishi.project.training.service.impl.AccelerationLogServiceImpl;
import com.weishi.tcp.vo.TcpMassageDataVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

@Service
public class SpeedometerServiceImpl implements ISpeedometerService {

    @Autowired
    private RedisCache redisCache;

    Logger logger = Logger.getLogger("Speedometer");

    @Autowired
    private ITrainingGroupChannelService trainingGroupChannelService;

    private ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);

    /**
     * 船速仪实时数据 接口
     */
    @Autowired
    private IShipSpeedRecordLogService shipSpeedRecordLogService;

    @Autowired
    private IAccelerationLogService accelerationLogService;

    @Autowired
    private ISportsmanService sportsmanService;

    @Autowired
    private IHeartRateService heartRateService;

    @Autowired
    private IWitAccLogService witAccLogService;

    private Map<Integer, List<ShipSpeedRecordLog>> gpsMap = new HashMap<>();

    private Map<Integer, List<AccelerationLog>> accelerationMap = new HashMap<>();
    private Map<Integer, List<WitAccLog>> witAccLogMap = new HashMap<>();

    //gps数据计算步长
    private int step = 20;

    //重力加速度
    private double g = 9.80665;


    /**
     * 根据船速仪 id 查询船速仪
     */
    @Override
    public AjaxResult selectRealTimeDataListById(String id) {
        List<ShipSpeedRecordLog> shipSpeedRecordLogList = shipSpeedRecordLogService.list(Wrappers.<ShipSpeedRecordLog>lambdaQuery().orderByDesc(ShipSpeedRecordLog::getId));

        double mm = GPSUtil.GetDistance1(shipSpeedRecordLogList.get(0).getLongitude(), shipSpeedRecordLogList.get(0).getLatitude(), shipSpeedRecordLogList.get(1).getLongitude(), shipSpeedRecordLogList.get(1).getLatitude());
        RealTimeDataVo realTimeDataVo = new RealTimeDataVo();
        realTimeDataVo.setDistance(mm);
        realTimeDataVo.setTime(0);

        return AjaxResult.success(realTimeDataVo);
    }

    @Override
    public void addRealTimeData(ShipSpeedRecordLog shipSpeedRecordLog) {
        //更新船速仪状态 5秒
        redisCache.setCacheObject(RedisConstants.ShipSpeed_Status_Prefix + shipSpeedRecordLog.getShipSpeedSn(), 1, 5, TimeUnit.SECONDS);

        //入库存储
        if (redisCache.getCacheObject(RedisConstants.Channel_ShipSpeed_Status_Prefix + shipSpeedRecordLog.getShipSpeedSn()) != null) {
            int channelId = redisCache.getCacheObject(RedisConstants.Channel_ShipSpeed_Status_Prefix + shipSpeedRecordLog.getShipSpeedSn());
            shipSpeedRecordLog.setChannelId(channelId);
            shipSpeedRecordLog.setCtime(new Date());
            shipSpeedRecordLogService.save(shipSpeedRecordLog);
        }
    }

    @Override
    public void addRealTimeData(List<TcpMassageDataVo> tcpMassageDataVos) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (TcpMassageDataVo tcpMassageDataVo : tcpMassageDataVos) {
                    addRealTimeData(tcpMassageDataVo);
                    logger.info("http数据上传：" + tcpMassageDataVo.toString());
                }
            }
        });

        thread.start();
    }

    @Override
    public void addRealTimeData(TcpMassageDataVo tcpMassageDataVo) {
        pool.execute(new Runnable() {
            @Override
            public void run() {
                DevInfo devInfo = selectRealTimeDataByDevId(tcpMassageDataVo.getDeviceId());
                if (TcpMassageDataVo.MsgTypeEnum.GPS.getMsgId().equals(tcpMassageDataVo.getMsgId())) {
                    //入库存储
                    try {
                        String[] data = tcpMassageDataVo.getFrom().split(":");
                        if (data.length > 2 && redisCache.getCacheObject(RedisConstants.Channel_ShipSpeed_Status_Prefix + tcpMassageDataVo.getDeviceId()) != null) {
                            int channelId = redisCache.getCacheObject(RedisConstants.Channel_ShipSpeed_Status_Prefix + tcpMassageDataVo.getDeviceId());
                            ShipSpeedRecordLog shipSpeedRecordLog = new ShipSpeedRecordLog();
                            shipSpeedRecordLog.setShipSpeedSn(tcpMassageDataVo.getDeviceId());
                            shipSpeedRecordLog.setLongitude(Double.parseDouble(data[0]));
                            shipSpeedRecordLog.setLatitude(Double.parseDouble(data[1]));
                            shipSpeedRecordLog.setSpeed(Double.parseDouble(data[2]));
                            shipSpeedRecordLog.setTimp(String.valueOf(tcpMassageDataVo.getTimp()));
                            shipSpeedRecordLog.setChannelId(channelId);
                            shipSpeedRecordLog.setCtime(new Date());
                            Date date = new Date(tcpMassageDataVo.getTimp());
                            shipSpeedRecordLog.setUtc(DateUtils.parseDateToStr("HHmmss.SSS", date));
                            getDistance(shipSpeedRecordLog, channelId);
                            shipSpeedRecordLog.setPropellerFrequency(devInfo.getPropellerFrequency());
                            shipSpeedRecordLogService.save(shipSpeedRecordLog);

                            devInfo.setDistance(shipSpeedRecordLog.getDistance());
                        }

                        //重置设备信息
                        devInfo.setStatus(1);
                        devInfo.setSpeed(Double.parseDouble(data[2]));
                        redisCache.setCacheObject(RedisConstants.Dev_Info_Prefix + tcpMassageDataVo.getDeviceId(), devInfo);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else if (TcpMassageDataVo.MsgTypeEnum.ACCELERATION.getMsgId().equals(tcpMassageDataVo.getMsgId())) {
                    //入库存储
                    try {
                        AccelerationLog accelerationLog = new AccelerationLog();
                        accelerationLog.setDevId(tcpMassageDataVo.getDeviceId());

                        String[] data = tcpMassageDataVo.getFrom().split(":");
//                    accelerationLog.setXcode(Double.parseDouble(data[0]));
//                    accelerationLog.setYcode(Double.parseDouble(data[1]));
                        accelerationLog.setZcode(Double.parseDouble(data[2]));
                        accelerationLog.setTimp(String.valueOf(tcpMassageDataVo.getTimp()));
                        int propellerFrequency = 0;
                        int channelId = 0;
                        if (redisCache.getCacheObject(RedisConstants.Channel_ShipSpeed_Status_Prefix + tcpMassageDataVo.getDeviceId()) != null) {
                            channelId = redisCache.getCacheObject(RedisConstants.Channel_ShipSpeed_Status_Prefix + tcpMassageDataVo.getDeviceId());
                            accelerationLog.setChannelId(channelId);
                            accelerationLog.setCtime(new Date());
                            accelerationLogService.save(accelerationLog);
                        }
                        propellerFrequency = getPropellerFrequency(accelerationLog, channelId);
                        //重置设备信息
                        devInfo.setStatus(1);
                        devInfo.setPropellerFrequency(propellerFrequency);
                        redisCache.setCacheObject(RedisConstants.Dev_Info_Prefix + tcpMassageDataVo.getDeviceId(), devInfo);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else if (TcpMassageDataVo.MsgTypeEnum.HEART.getMsgId().equals(tcpMassageDataVo.getMsgId())) {
                    Sportsman sportsman = sportsmanService.getSportsmanByPolarId(tcpMassageDataVo.getDeviceId());
                    if (sportsman != null) {
                        int heart = Integer.parseInt(tcpMassageDataVo.getFrom());
                        sportsmanService.setHeartCount(sportsman.getId(), heart);
                        try {
                            Integer channelId = redisCache.getCacheObject(RedisConstants.Heart_Rate_Meter_Prefix + sportsman.getId());
                            if (channelId != null) {
                                HeartRate heartRate = new HeartRate();
                                heartRate.setSportsmanId(sportsman.getId());
                                heartRate.setDeviceId(tcpMassageDataVo.getDeviceId());
                                heartRate.setChannelId(channelId);
                                heartRate.setHr(heart);
                                heartRate.setCtime(new Date());
                                Integer countId = redisCache.getCacheObject(RedisConstants.Channel_count_Prefix + channelId);
                                if (countId == null) {
                                    countId = 1;
                                }
                                heartRate.setHeartRateCountId(countId);
                                heartRate.setTime(String.valueOf(tcpMassageDataVo.getTimp()));
                                heartRateService.save(heartRate);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
    }

    @Override
    public void addRealTimeData(MqttDataVo mqttDataVo) {
        pool.execute(new Runnable() {
            @Override
            public void run() {
                logger.info(mqttDataVo.toString());
                DevInfo devInfo = selectRealTimeDataByDevId(mqttDataVo.getDevId());
                if (TcpMassageDataVo.MsgTypeEnum.GPS.getMsgId().equals(mqttDataVo.getType())) {
                    //入库存储
                    try {
                        String[] data = mqttDataVo.getDatas();
                        if (redisCache.getCacheObject(RedisConstants.Channel_ShipSpeed_Status_Prefix + mqttDataVo.getDevId()) != null) {
                            int channelId = redisCache.getCacheObject(RedisConstants.Channel_ShipSpeed_Status_Prefix + mqttDataVo.getDevId());
                            ShipSpeedRecordLog shipSpeedRecordLog = new ShipSpeedRecordLog();
                            shipSpeedRecordLog.setShipSpeedSn(mqttDataVo.getDevId());
                            shipSpeedRecordLog.setLongitude(Double.parseDouble(data[2]));
                            shipSpeedRecordLog.setLatitude(Double.parseDouble(data[3]));
                            shipSpeedRecordLog.setSpeed(Double.parseDouble(data[4]));
                            shipSpeedRecordLog.setTimp(mqttDataVo.getTimeTimp());
                            shipSpeedRecordLog.setChannelId(channelId);
                            shipSpeedRecordLog.setCtime(new Date());
                            Date date = new Date(Long.parseLong(mqttDataVo.getTimeTimp()));
                            shipSpeedRecordLog.setUtc(DateUtils.parseDateToStr("HHmmss.SSS", date));
                            getDistance(shipSpeedRecordLog, channelId);
                            shipSpeedRecordLog.setPropellerFrequency(devInfo.getPropellerFrequency());
                            shipSpeedRecordLogService.save(shipSpeedRecordLog);

                            devInfo.setDistance(shipSpeedRecordLog.getDistance());
                        }

                        //重置设备信息
                        devInfo.setStatus(1);
                        devInfo.setSpeed(Double.parseDouble(data[4]));
                        redisCache.setCacheObject(RedisConstants.Dev_Info_Prefix + mqttDataVo.getDevId(), devInfo);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else if (TcpMassageDataVo.MsgTypeEnum.ACCELERATION.getMsgId().equals(mqttDataVo.getType())) {
                    //入库存储
                    try {
                        AccelerationLog accelerationLog = new AccelerationLog();
                        accelerationLog.setDevId(mqttDataVo.getDevId());
                        String[] data = mqttDataVo.getDatas();
                        accelerationLog.setXcode(Double.parseDouble(data[2]));
                        accelerationLog.setYcode(Double.parseDouble(data[3]));
                        accelerationLog.setZcode(Double.parseDouble(data[4]));
                        accelerationLog.setTimp(String.valueOf(mqttDataVo.getTimeTimp()));
                        int propellerFrequency = 0;
                        int channelId = 0;
                        if (redisCache.getCacheObject(RedisConstants.Channel_ShipSpeed_Status_Prefix + mqttDataVo.getDevId()) != null) {
                            channelId = redisCache.getCacheObject(RedisConstants.Channel_ShipSpeed_Status_Prefix + mqttDataVo.getDevId());
                            accelerationLog.setChannelId(channelId);
                            accelerationLog.setCtime(new Date());
                            accelerationLogService.save(accelerationLog);
                        }

                        if(devInfo.getPropellerFrequencyFlag()==0){
                            propellerFrequency = getPropellerFrequency(accelerationLog, channelId);
                            devInfo.setPropellerFrequency(propellerFrequency);
                        }
                        //重置设备信息
                        devInfo.setStatus(1);
                        redisCache.setCacheObject(RedisConstants.Dev_Info_Prefix + mqttDataVo.getDevId(), devInfo);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else if (TcpMassageDataVo.MsgTypeEnum.HEART.getMsgId().equals(mqttDataVo.getType())) {
                    Sportsman sportsman = sportsmanService.getSportsmanByPolarId(mqttDataVo.getDevId());
                    if (sportsman != null) {
                        int heart = Integer.parseInt(mqttDataVo.getDatas()[2]);
                        sportsmanService.setHeartCount(sportsman.getId(), heart);
                        try {
                            Integer channelId = redisCache.getCacheObject(RedisConstants.Heart_Rate_Meter_Prefix + sportsman.getId());
                            if (channelId != null) {
                                HeartRate heartRate = new HeartRate();
                                heartRate.setSportsmanId(sportsman.getId());
                                heartRate.setDeviceId(mqttDataVo.getDevId());
                                heartRate.setChannelId(channelId);
                                heartRate.setHr(heart);
                                heartRate.setCtime(new Date());
                                Integer countId = redisCache.getCacheObject(RedisConstants.Channel_count_Prefix + channelId);
                                if (countId == null) {
                                    countId = 1;
                                }
                                heartRate.setHeartRateCountId(countId);
                                heartRate.setTime(String.valueOf(mqttDataVo.getTimeTimp()));
                                heartRateService.save(heartRate);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                } else if (TcpMassageDataVo.MsgTypeEnum.WIT_ACC.getMsgId().equals(mqttDataVo.getType())) {
                    try {
                        WitAccLog witAccLog = new WitAccLog();
                        String[] datas = mqttDataVo.getDatas();
                        witAccLog.setDevId(datas[1]);
                        witAccLog.setTimp(datas[2]);
                        String[] as = datas[3].split(":");
                        witAccLog.setAx(Double.parseDouble(as[0]));
                        witAccLog.setAy(Double.parseDouble(as[1]));
                        witAccLog.setAz(Double.parseDouble(as[2]));

                        String ws[] = datas[4].split(":");
                        witAccLog.setWx(Double.parseDouble(ws[0]));
                        witAccLog.setWy(Double.parseDouble(ws[1]));
                        witAccLog.setWz(Double.parseDouble(ws[2]));

                        String angles[] = datas[5].split(":");
                        witAccLog.setAnglex(Double.parseDouble(angles[0]));
                        witAccLog.setAngley(Double.parseDouble(angles[1]));
                        witAccLog.setAnglez(Double.parseDouble(angles[2]));
                        int channelId = 0;
                        if (redisCache.getCacheObject(RedisConstants.Channel_ShipSpeed_Status_Prefix + mqttDataVo.getDevId()) != null) {
                            channelId = redisCache.getCacheObject(RedisConstants.Channel_ShipSpeed_Status_Prefix + mqttDataVo.getDevId());
                            witAccLog.setChannelId(channelId);
                            witAccLog.setCtime(new Date());
                            witAccLogService.save(witAccLog);
                        }
                        int propellerFrequency = getPropellerFrequency(witAccLog, channelId);
                        devInfo.setPropellerFrequency(propellerFrequency);
                        devInfo.setPropellerFrequencyFlag(1);
                        redisCache.setCacheObject(RedisConstants.Dev_Info_Prefix + mqttDataVo.getDevId(), devInfo);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });

    }

    @Override
    public DevInfo selectRealTimeDataByDevId(String devId) {
        DevInfo devInfo = null;
        try {
            devInfo = redisCache.getCacheObject(RedisConstants.Dev_Info_Prefix + devId);
            if (devInfo == null) {
                devInfo = new DevInfo();
                devInfo.setRealTime("0:0:0");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return devInfo;
    }

    /**
     * 查询gps距离（每step个点作为基准距离）
     *
     * @param gps
     * @return
     */
    private double getDistance(ShipSpeedRecordLog gps, int channelId) {
        List<ShipSpeedRecordLog> gpsList = gpsMap.get(channelId);
        if (gpsList == null) {
            gpsList = new ArrayList<>();
            gpsMap.put(channelId, gpsList);
        }
        double distance = 0.0d;
        try {
            if (gpsList.size() > 0 && gpsList.get(0).getDistance() != 0.0d) {
                ShipSpeedRecordLog vo = gpsList.get(0);
                double distanceTemp = GPSUtil.GetDistance1(vo.getLatitude(), vo.getLongitude(), gps.getLatitude(), gps.getLongitude());
                distance = distanceTemp + vo.getDistance();
                gps.setDistance(distance);
            }

            if (gpsList.size() == 0) {
                gps.setDistance(0.001d);
            }

            if (gpsList.size() > step) {
                gpsList.clear();
            }

            gpsList.add(gps);
        } catch (Exception e) {

            e.printStackTrace();
        }
        return distance;
    }

    /**
     * 查询每分钟的平均桨频
     *
     * @param accelerationLog
     * @return
     */
    private int getPropellerFrequency(AccelerationLog accelerationLog, int channel) {
        int propellerFrequency = 0;
        try {
            List<AccelerationLog> accelerationList = accelerationMap.get(channel);
            if (accelerationList == null) {
                accelerationList = new ArrayList<>();
            }
            accelerationList.add(accelerationLog);
            accelerationMap.put(channel, accelerationList);

            Collections.sort(accelerationList, new Comparator<AccelerationLog>() {
                @Override
                public int compare(AccelerationLog o1, AccelerationLog o2) {
                    return o1.getTimp().compareTo(o2.getTimp());
                }
            });

            propellerFrequency = accelerationLogService.qryCurrentPropellerFrequency(accelerationList);

            if (accelerationList.size() > 1000) {
                List<AccelerationLog> accelerationListTemp = accelerationList.subList(500, accelerationList.size());
                accelerationMap.put(channel, accelerationListTemp);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return propellerFrequency;
    }

    private int getPropellerFrequency(WitAccLog witAccLog, int channel) {
        int propellerFrequency = 0;
        try {
            List<WitAccLog> witAccLogList = witAccLogMap.get(channel);
            if (witAccLogList == null) {
                witAccLogList = new ArrayList<>();
            }
            witAccLogList.add(witAccLog);
            witAccLogMap.put(channel, witAccLogList);

            Collections.sort(witAccLogList, new Comparator<WitAccLog>() {
                @Override
                public int compare(WitAccLog o1, WitAccLog o2) {
                    return o1.getTimp().compareTo(o2.getTimp());
                }
            });

            propellerFrequency = witAccLogService.qryCurrentPropellerFrequency(witAccLogList);

            if (witAccLogList.size() > 2000) {
                List<WitAccLog> witAccLogListTemp = witAccLogList.subList(1000, witAccLogList.size());
                witAccLogMap.put(channel, witAccLogListTemp);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return propellerFrequency;
    }

}
